//
// Created by lwj12 on 24-9-15.
//

#ifndef SMARTPTR_SHAREDPTR_H
#define SMARTPTR_SHAREDPTR_H
#include <iostream>
#include <functional>

using namespace std;

namespace lwj
{
    template<class T>
    class shared_ptr
    {
    public:
        shared_ptr(T* ptr)
                : _ptr(ptr),
                  _pcount(new int(1))
        {}

        template<class D>
        shared_ptr(T* ptr, D del)
            : _ptr(ptr),
              _pcount(new int(1)),
              _del(del)
        {}

        void release()
        {
            if(--(*_pcount) == 0)
         {
             _del(_ptr);
             delete _pcount;
             _ptr = _pcount = nullptr;
         }
        }

     shared_ptr(const shared_ptr& sp)
         : _ptr(sp._ptr),
           _pcount(sp._pcount),
           _del(sp._del)
     {++(*_pcount);}

     ~shared_ptr() {release();}

        shared_ptr& operator=(const shared_ptr& sp)
        {
            release();
            _ptr = sp._ptr;
            _pcount = sp._pcount;
            _del = sp._del;
            ++(*_pcount);
            return *this;
        }

        T* get() {return _ptr;}
        int use_count() {return *_pcount;}

        T* operator->() {return _ptr;}
        T& operator*() {return *_ptr;}

    private:
        T* _ptr;
        int* _pcount;
        function<void(T*)> _del = [](T* ptr) {delete ptr;};
    };

    template<class T>
    class weak_ptr
    {
    public:
        weak_ptr() {}

        weak_ptr(const shared_ptr<T>& sp)
                :_ptr(sp.get())
        {}

        weak_ptr& operator=(const shared_ptr<T>& sp) {_ptr = sp.get();return *this;}
    private:
        T* _ptr;
    };
}

#endif//SMARTPTR_SHAREDPTR_H
